# -*- coding:utf-8 -*-
from ui_cali import Ui_MultiBaseCalibration
import datetime, copy, os
from PyQt5 import QtWidgets,QtSql,QtGui,QtCore
from PyQt5.QtCore import Qt
import logging
from FlowLayout import FlowLayout
import myglobal
import mydb
import pyqtgraph as pg
from delegates import CheckBoxDelegateQt
import numpy as np
import least
import traceback
import getpath
import myglobal
import config_json
import time
pg.setConfigOption('leftButtonPan', False)
def sort_by_x(idx,x,y):
    # print(idx,x,y)
    data=np.stack([idx,x,y],axis=1)
    # print(data)
    data = data[data[:, 1].argsort()]
    # print(data)
    idx=data[ :,0]
    x=data[ :,1]
    y=data[ :,2]
    return idx,x,y    
class Cali(QtWidgets.QDialog, ):
    ui = Ui_MultiBaseCalibration()
    def __init__(self):
        super().__init__()
        self.ui.setupUi(self)
        self.curveid=0
        self.plot=None
        self.at=0
        self.ele=None
        self.idx=[]
        self.setWindowTitle('校正')
        self.clickedPen = pg.mkPen('b', width=2)
        # self.db=mydb.MyDb()
        self.model2 = QtSql.QSqlQueryModel(self)
        self.ui.tableView_curve.setModel(self.model2)
        self.ui.tableView_curve.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)

        selection_model = self.ui.tableView_curve.selectionModel()
        selection_model.currentRowChanged.connect(self.curveid_change)
        self.model = QtSql.QSqlTableModel()
        self.model.setTable("curvedata")  # setQuery(cmd)
        self.model.setEditStrategy(QtSql.QSqlTableModel.EditStrategy.OnFieldChange)
        self.ui.twData.setModel(self.model)
        self.ui.twData.setSortingEnabled(True)
        self.checkDele=CheckBoxDelegateQt()
        self.ui.twData.setItemDelegateForColumn(6,self.checkDele)
        myglobal.fields=self.to_fields(myglobal.db.table_info("STD"))
        logging.info(myglobal.fields)
        self.ui.btnCalculation.clicked.connect(self.calc_click)
        # self.btnDelete.clicked.connect(self.btnDelete_clicked)
        self.ui.pushButton_std_result.clicked.connect(self.show_std_result)
        self.ui.pushButton_std.clicked.connect(self.show_std)  
        # self.ui.pushButton_select.clicked.connect(self.show_std_result)                
        self.ui.pushButton_del.clicked.connect(self.delCurve) 
        self.ui.pushButton_delete.clicked.connect(self.delCurveDataOne) 
        self.ui.pushButton_delAll.setVisible(False)#clicked.connect(self.delCurveData) 
        self.ui.pushButton_add.setVisible(False)# clicked.connect(self.addCurveDataOne) 
        self.ui.pushButton_add00.clicked.connect(self.add00) 

        self.ui.pushButton_select.setVisible(False) 
        self.ui.btnNew.setVisible(False) 
        self.ui.btnDelete.setVisible(False) 
        self.h = FlowLayout(self.ui.groupBox)
        self.chks = []
        self.model.setSort(4,Qt.DescendingOrder)#AscendingOrder)
        self.add_pgw()
        self.resize(1000,1000)
        self.resetItems()
        self.ui.pushButton_unuse.clicked.connect(self.remove_point) 
        self.ui.pushButton_addCurve.clicked.connect(self.addSecondCurve)
        # self.ui.pushButton_delcurve.setVisible(False)
        self.firstChannel()# here todo
    def curveid_change(self,current):
        logging.info("method_change")
        # selections = self.ui.tableView_method.selectionModel()
        # list1 = selections.selectedIndexes()
        # for i in range(len(list1)):
        #     current = list1[i]
        row = current.row()
        record = self.model2.record(row)
        idCol = record.indexOf("curveid")  #
        id1 = record.value(idCol)
        # self.ids.remove(id1)
        if self.curveid==id1:
            pass
        else:
            self.curveid=id1
            cmd="update ele_curve set curveid=%d where methodid=%d and ele='%s'" %(self.curveid,myglobal.methodid,self.ele)
            myglobal.db.sql_cmd(cmd)
            self.showCurrent()
    def addSecondCurve(self):
        logging.info(["begin",time.perf_counter()])
        ids=myglobal.db.getAllCurveid(myglobal.methodid,self.ele)
        if len(ids)==0:
            self.curveid=0
        else:
            id_max=np.max(ids)
            self.curveid=id_max+1
        myglobal.db.setCurveid(myglobal.methodid,self.ele,self.curveid)#sql_cmd("insert into ele_curve(methodid,ele,curveid) values(%d,'%s',%d)" %(myglobal.methodid,self.ele,self.curveid))
        self.genCurveData()
        self.calc()
        self.showCurrent()
        logging.info(["end",time.perf_counter()])
    def show_manycurve(self):
        self.model2.setQuery("select methodid,ele,curveid from curvexishu where methodid=%s and ele='%s'" %(myglobal.methodid,self.ele))
        self.ui.tableView_curve.setColumnWidth(0,70)
        self.ui.tableView_curve.setColumnWidth(1,50)
    def closeEvent(self, event):
        myglobal.cali=None
        event.accept()
    def delCurveDataOne(self):
        print("delCurveDataOne")
        selections = self.ui.twData.selectionModel()
        list1 = selections.selectedIndexes()
        ids=[]
        for i in range(len(list1)):
            current = list1[i]
            row = current.row()
            record = self.model.record(row)
            idCol = record.indexOf("id")  #
            id1 = record.value(idCol)
            print(id1)
            cmd="""delete from  curvedata where id=%d""" % (id1)
            myglobal.db.sql_cmd(cmd)
            break
        self.model.select()
    # def delCurveData(self):
    #     print("delCurveData")
    #     cmd="""delete from  curvedata  where methodid=%d and ele='%s' and curveid=%d""" % (myglobal.methodid,self.ele,self.curveid)
    #     myglobal.db.sql_cmd(cmd)
    #     self.model.select()
    #     self.delCurve()
    def addCurveDataOne(self):
        cmd="""insert into curvedata(methodid,ele,use,curveid) values(%d,'%s',1,%d)""" % (myglobal.methodid,self.ele,self.curveid)
        myglobal.db.sql_cmd(cmd)
        self.model.select()
        pass
    def add00(self):
        cmd="""insert into curvedata(methodid,ele,use,curveid,ele_std,ele_measure) values(%d,'%s',1,%d,0,0)""" % (myglobal.methodid,self.ele,self.curveid)
        myglobal.db.sql_cmd(cmd)
        self.model.select()
        # pass

    def genCurveData(self):
        myglobal.db.std_result_to_curvedata(myglobal.methodid, self.ele,self.curveid)
        self.model.setFilter("curveid="+str(self.curveid)+" and methodid="+str(myglobal.methodid)+ " and ele =  '" + self.ele+"'")
        self.model.select()
        # self.calc()
        # self.showCurrent()
    def pgWidget(self):
        pg.setConfigOptions(imageAxisOrder='row-major')
        win = pg.GraphicsLayoutWidget()
        win.setWindowTitle('pyqtgraph example: Image Analysis')
        self.fig= win.addPlot(title="")
        self.fig.enableAutoRange()
        return win
    def add_pgw(self):#put pgw on widget
        v = QtWidgets.QVBoxLayout(self.ui.widget)
        self.pgw=self.pgWidget()

        v.addWidget(self.pgw)
        self.ui.widget.setLayout(v)
    def delCurve(self):
        curveid=myglobal.db.del_curve(myglobal.methodid,self.ele,self.curveid)
        # ids=myglobal.db.getAllCurveid(myglobal.methodid,self.ele)
        if curveid!=None:
            self.curveid=curveid
        else:
            self.curveid=0
        self.showCurrent()
    def showFigNone(self):
        self.fig.clear()
        self.ui.lblParams.setText("")      
    def showCurve(self):
        xishu=myglobal.db.getXishu(myglobal.methodid,self.ele,self.curveid)
        if xishu!=None:
            self.showxishu(xishu)
            [x2,x1,x0,r,curveid,must00,ci]=xishu
            print(xishu)
            x=[]
            y=[]
            self.idx=[]
            y_fitted=[]
            for row in range(self.model.rowCount()):
                record = self.model.record(row)
                x1= myglobal.myfloat(record.value(4))
                y1= myglobal.myfloat(record.value(3))
                y2= myglobal.myfloat(record.value(5))
                use= record.value(6)
                if use==1:
                    # if x1==0 or y1==0:
                    #     pass
                    # else:
                    x.append(x1)
                    y.append(y1)
                    y_fitted.append(y2)
                    self.idx.append(row)
            if must00:
                print("insert 0,0")
                x.append(0)#insert(0,0)
                y.append(0)#insert(0,0)
                y_fitted.append(0)#insert(0,0)
                self.idx.append(-1)#insert(0,-1)
            self.show_fig(x,y,y_fitted)
        else:
            self.showFigNone()
    def curvedata_arr(self):
        x=[]
        y=[]
        self.idx=[]
        for row in range(self.model.rowCount()):
            record = self.model.record(row)
            # id1= record.value(0)
            x1= record.value(4)
            y1= record.value(3)
            use= record.value(6)
            if use==1:
                x1f=myglobal.to_float(x1)
                y1f=myglobal.to_float(y1)
                if x1f!=None and y1f!=None:
                    x.append(x1f)
                    y.append(y1f)
                    self.idx.append(row)
                else:
                    # cmd="update curvedata set use=0 where id=%d" % id1
                    # myglobal.db.sql_cmd(cmd)   
                    self.model.setData(self.model.index(row,self.model.fieldIndex("use")), 0) #use to 0
                    # logging.info([row,mass,m])
                    self.model.submitAll() 
                    pass
        x=np.array(x)
        y=np.array(y)
        return(x,y)
    def calcXY(self,x,y):
        # logging.info(time.perf_counter())
        if self.ui.radioButton_1.isChecked():
            m=1
        else:
            m=2
        must00=False
        if self.ui.checkBox_must00.isChecked():
            must00=True
        print(must00)
        w=[1 for x1 in x]
        if must00:
            x=np.append(x,0)#.append(0)
            y=np.append(y,0)#y.append(0)
            w=np.append(w,100000000)#.append(10000)
        lfit_r=least.lfit(x,y,m,w)
        if lfit_r:
            (xishu,r,y_fitted)=lfit_r
        else:
            #fit error
            xishu=[0,1,0]
            y_fitted=x 
            r=0
        # logging.info(["after lfit",time.perf_counter()])
        i=0
        for row in self.idx:
            y_fit=float(y_fitted[i])#class 'numpy.float64'
            self.model.setData(self.model.index(int(row),self.model.fieldIndex("ele_calc")),y_fit)# y_fitted[i]) #mass
            self.model.submitAll()
            # record = self.model.record(row)
            # id1= record.value(0)
            # cmd="update curvedata set ele_calc=%f where id=%d" % (y_fit,id1)
            # myglobal.db.sql_cmd(cmd)
            i+=1
        if m==1:
            x2=0
            x1=xishu[0]
            x0=xishu[1]
        else:
            x2=xishu[0]
            x1=xishu[1]
            x0=xishu[2]
        # logging.info(["before show_fig",time.perf_counter()])
        print(y_fitted)
        self.show_fig(x,y,y_fitted)
        # logging.info(["after show_fig",time.perf_counter()])
        self.showxishu([x2,x1,x0,r,self.curveid,must00,m])
        # logging.info(["after showxishu",time.perf_counter()])
        myglobal.db.save_xishu(myglobal.methodid,self.ele,x2,x1,x0,r,self.curveid,must00,m)  
        # self.chks[self.at].setStyleSheet('QRadioButton { background-color: red }')
        # self.show_manycurve()    
    def calc_click(self):
        logging.info(["begin",time.perf_counter()])
        self.calc()
        self.showCurrent()    
    def calc(self):
        logging.info(time.perf_counter())
        (x,y)=self.curvedata_arr()
        self.calcXY(x,y)
    # def myfit(self,x,y,m):
    #     (xishu,r,y_fitted)=least.lfit(x,y,m)
    #     # y_fitted=[]
    #     # for x1 in x:
    #     #     if m==1:
    #     #         y=xishu[1]*x1+xishu[0]
    #     #     else:
    #     #         y=xishu[2]*x1*x1+xishu[1]*x1+xishu[0]
    #     #     y_fitted.append(y)
    #     return (xishu,r,y_fitted)
    def showxishu(self,xishu):
        [x2,x1,x0,r,curveid,must00,ci]=xishu
        params=""
        params+="x2="+str(x2)+"\n"
        params+="x1="+str(x1)+"\n"
        params+="x0="+str(x0)+"\n"
        params+="r="+str(r)+"\n"
        if must00:
            self.ui.checkBox_must00.setChecked(True)
        else:
            self.ui.checkBox_must00.setChecked(False)
        if ci==1:
            self.ui.radioButton_1.setChecked(True)
        elif ci==2:
            self.ui.radioButton_2.setChecked(True)
        self.ui.lblParams.setText(params)
    def remove_point(self):
        deleted=False
        logging.info(time.perf_counter())
        for p in self.lastClicked:
            row=self.idx[p.index()]
            self.model.setData(self.model.index(row,self.model.fieldIndex("use")), 0)
            self.model.submitAll()
            deleted=True
        self.lastClicked=[]
        if deleted:
            self.calc()
    def clicked(self,plot, points):
        for p in self.lastClicked:
            p.resetPen()
        print("clicked points", points)
        for p in points:
            p.setPen(self.clickedPen)
            print(dir(p),p.pos(),p.index(),self.idx[p.index()])
        self.lastClicked = points        
    def show_fig(self,x,y,y_fitted):
        self.lastClicked=[]
        self.fig.clear()
        # print(dir(self.fig))
        # if self.plot!=None:
        #     self.fig.addItem(self.plot)    
        # else:
        #     self.fig.addItem(self.plot)    
        self.plot = pg.ScatterPlotItem(
            size=15, brush=pg.mkBrush(30, 255, 35, 255))
        self.plot.sigClicked.connect(self.clicked)
        # data for x-axis
 
        # adding spots to the scatter plot
        self.plot.addPoints(x,y)#_data, y_data)
 
        # add item to plot window
        # adding scatter plot item to the plot window
        self.fig.addItem(self.plot)
        # self.plot=self.fig.plot(x=x, y=y, pen=None, symbol='o')
        # print(dir(self.plot),self.plot)
        self.fig.plot(x=x, y=y_fitted, pen=pg.mkPen(color="r", width=2), style=Qt.DashLine)
        self.fig.autoRange()
    def to_fields(self,data):
        fields = [{"ele": None, "name": "id", "title": "id", "visible": False
                        }, {"ele": None, "name": "sampleid", "title": "样品编号", "visible": True
                            }, {"ele": None, "name": "beizhu", "title": "备注", "visible": True
                                }]       
        if len(data)>2:
            for one in data[2:]:
                fields.append({"ele": one[:-1], "name": one, "title": one[:-1], "visible": True})
        return fields        
    def genchks(self):
        if len(self.chks) < len(myglobal.fields):
            # logging.info(list(range(len(self.chks), len(self.fields))))
            for i in range(len(self.chks), len(myglobal.fields)):
                c = QtWidgets.QRadioButton("")
                self.h.addWidget(c)
                c.pressed.connect(
                    lambda val=i: self.field_click(val)
                )
                self.chks.append(c)
    def firstChannel(self):
        at=0
        for i in range(len(myglobal.fields)):
            if myglobal.fields[i].get("ele") is None:
                pass
            else:
                at=i
                break
        self.field_click(at)
    def field_click(self, i):
        self.at=i
        logging.info(self.sender())
        logging.info(i)
        # logging.info(myglobal.fields[i]["visible"])
        # myglobal.fields[i]["visible"] = True
        logging.info(myglobal.fields[i]["ele"])
        self.ele=myglobal.fields[i]["ele"]
        self.curveid=myglobal.db.getCurveid(myglobal.methodid,self.ele)
        self.showCurrent()
    def showCurrent(self):
        logging.info([myglobal.methodid,self.ele,self.curveid])
        self.model.setFilter("curveid="+str(self.curveid)+" and methodid="+str(myglobal.methodid)+ " and ele =  '" + self.ele+"'")
        # self.model.select()
        self.showCurve()
        self.show_manycurve()
        if config_json.setting["xishu_state"]==1:
            xishu=myglobal.db.getXishuCurrent(myglobal.methodid,self.ele)
            if xishu==None:
                self.chks[self.at].setStyleSheet('QRadioButton { background-color: green }')
            else:
                self.chks[self.at].setStyleSheet('QRadioButton { background-color: red }')
    def resetItems(self):
        self.genchks()
        logging.info(len(self.chks))
        firstEle=True
        for i in range(len(myglobal.fields)):
            ele=myglobal.fields[i].get("ele")
            if ele is None:
                self.chks[i].setVisible(False)
            else:
                if firstEle:
                    self.chks[i].setChecked(True)
                    self.chks[i].setText(myglobal.fields[i]["title"])
                    self.chks[i].setVisible(True)
                    firstEle=False
                else:
                    self.chks[i].setChecked(False)
                    self.chks[i].setText(myglobal.fields[i]["title"])
                    self.chks[i].setVisible(True)
        for i in range(len(myglobal.fields), len(self.chks)):
            self.chks[i].setVisible(False)
        self.showXishuState()
    def showXishuState(self):
        if config_json.setting["xishu_state"]==1:
            for i in range(len(myglobal.fields)):
                ele=myglobal.fields[i].get("ele")
                if ele is None:
                    pass
                else:
                    xishu=myglobal.db.getXishuCurrent(myglobal.methodid,ele)
                    if xishu is None:
                        self.chks[i].setStyleSheet('QRadioButton { background-color: green }')
                    else:
                        self.chks[i].setStyleSheet('QRadioButton { background-color: red }')
    def showXishuStateNone(self):
        for i in range(len(myglobal.fields)):
            ele=myglobal.fields[i].get("ele")
            if ele is None:
                pass
            else:
                self.chks[i].setStyleSheet('QRadioButton { background-color: green }')
    def import_std_result(self):
        FileDialog =QtWidgets.QFileDialog(self)
        folder=os.path.join(os.curdir)#os.path.expanduser('~'), "Desktop")
        fil = "xlsx Files (*.xlsx);;All Files (*)"
        FileDirectory = FileDialog.getOpenFileName(
            self, 'select import file', folder, fil)  # 选择目录，返回选中的路径
        fname = FileDirectory[0]
        if fname == "":
            pass
        else:
            try:
                myglobal.methodid=myglobal.db.methodid()
                myglobal.db.import_std_result_file2(fname)
            except:
                traceback.print_exc()
    def show_std(self):
        from dlgstd import DlgStd
        d = DlgStd()
        r = d.exec_()
    def show_std_result(self):
        from dlgstd_result import DlgStd_result
        d = DlgStd_result()
        r = d.exec_()
        if r == 1:
            logging.info(r)
            myglobal.db.sql_cmd("delete  from curvedata where methodid=%d" % myglobal.methodid)
            myglobal.db.sql_cmd("delete  from curvexishu where methodid=%d" % myglobal.methodid)
            at=0
            for i in range(len(myglobal.fields)):
                if myglobal.fields[i].get("ele") is None:
                    pass
                else:
                    at=i
                    myglobal.db.std_result_to_curvedata(myglobal.methodid, myglobal.fields[i].get("ele"))
            self.model.select()
            self.model.setFilter("methodid="+str(myglobal.methodid)+ " and ele =  '" + myglobal.fields[at]["ele"]+"'")
            self.showXishuStateNone()
            self.firstChannel()
        # else:
        self.firstChannel()
        self.showXishuState()
        pass

    def import_std(self):
        FileDialog =QtWidgets.QFileDialog(self)
        folder=os.path.join(os.curdir)#os.path.expanduser('~'), "Desktop")
        fil = "xlsx Files (*.xlsx);;All Files (*)"
        FileDirectory = FileDialog.getOpenFileName(
            self, 'select import file', folder, fil)  # 选择目录，返回选中的路径
        fname = FileDirectory[0]
        if fname == "":
            pass
        else:
            try:
                myglobal.db.import_std_file(fname)
            except:
                traceback.print_exc() 

    def btnNew_clicked(self):
        '''新建一条数据'''
        data = BaseCalibrationItem()
        data.id = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        data.standard = 0.012
        data.area = 0.011
        data.input = True
        data.include = True
        self.setDatas([data])
        self.baseItems[self.currentChannel].append(data)

    def btnDelete_clicked(self):
        ranges = self.twData.selectedRanges()
        count = len(ranges)
        row = []
        for i in range(0, count):
            for j in range(ranges[i].topRow(), ranges[i].bottomRow() + 1):
                row.append(j)
        row.sort(key=int, reverse=True)  # 因为删除一行后，后面的行号都会变化，所以用sort方法将list进行降序排列
        self.twData.blockSignals(True)
        for i in row:
            self.twData.removeRow(i)
            self.baseItems[self.currentChannel].pop(i)
        self.twData.blockSignals(False)


    def dropEvent(self, a0) -> None:
        """当拖拽操作在目标控件上被释放时，触发"""
        if a0.mimeData().hasText():
            dropstr = a0.mimeData().text()
            # print(dropstr)
            rowindexsstr = dropstr.split("&")
            rowIndexs = []
            for i in rowindexsstr:
                rowIndexs.append(int(i))
            count = len(rowIndexs)
            if count > 0:
                results = device.modelResult.getBaseItems(rowIndexs)
                if len(results) > 0:
                    self.setDatas(results)
                    for i in results:
                        self.baseItems[self.currentChannel].append(i)
        pass

    def dragEnterEvent(self, a0) -> None:
        """拖拽操作时，进入该控件时，触发该事件，"""
        if a0.mimeData().hasText():
            a0.setAccepted(True)
            # print("准备接收drag")
        else:
            a0.setAccepted(False)
            # print("drag不匹配")
        pass
if __name__ == '__main__':
    import sys
    import logging
    import getpath
    initpath=getpath.getpath()
    import logging
    import config_json
    from logging.handlers import RotatingFileHandler
    handlers=[RotatingFileHandler(filename="report.log", maxBytes=10*1024*1024, encoding='utf-8',backupCount=3),# logging.FileHandler(initpath+'/myapp.log'),
        logging.StreamHandler(sys.stdout)]
    logging.basicConfig(level=logging.DEBUG,
                        format = '%(asctime)s - %(name)s - %(levelname)s -%(funcName)s - %(message)s',
                        handlers=handlers)
    logging.info('begin')
    app = QtWidgets.QApplication(sys.argv)
    w = Cali()
    w.setAttribute(Qt.WA_DeleteOnClose)
    w.exec()
    sys.exit(0)
